//
//  UITableViewCell+DWAutoHeight.m
//  DWCellHeightDemo
//
//  Created by 吴涛 on 16/2/15.
//  Copyright © 2016年 Duke.Wu. All rights reserved.
//

#import "UITableViewCell+DWAutoHeight.h"
#import <objc/runtime.h>
#import "UITableView+BKJDWCacheHeight.m"

@implementation UITableViewCell (DWAutoHeight)

// associative 扩展属性用
const void *s_dw_bottomViewKey = "dw_bottomViewKey";
const void *s_dw_bottomOffsetToCellKey = "dw_bottomOffsetToCellKey";

#pragma mark - Public Methods

+ (CGFloat)dw_heightForIndexPath:(NSIndexPath *)indexPath config:(DWCellConfigBlock)config{
  
  UITableViewCell *cell = [[self alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
  
  config(cell);
  
  return [cell private_dw_heightForIndexPath:indexPath];
}

// associative 扩展属性用
- (void)setDw_bottomView:(UIView *)dw_bottomView{
  objc_setAssociatedObject(self,
                           s_dw_bottomViewKey,
                           dw_bottomView,
                           OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

- (UIView *)dw_bottomView {
  return objc_getAssociatedObject(self, s_dw_bottomViewKey);
}


- (void)setDw_bottomOffsetToCell:(CGFloat)dw_bottomOffsetToCell {
  objc_setAssociatedObject(self,
                           s_dw_bottomOffsetToCellKey,
                           @(dw_bottomOffsetToCell),
                           OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (CGFloat)dw_bottomOffsetToCell {
  NSNumber *valueObject = objc_getAssociatedObject(self, s_dw_bottomOffsetToCellKey);
  if ([valueObject respondsToSelector:@selector(floatValue)]) {
    return valueObject.floatValue;
  }
  
  return 0.0;
}



+ (CGFloat)dw_heightForTableView:(UITableView *)tableView config:(DWCellConfigBlock)config {
  UITableViewCell *cell = [tableView.dw_reuseCells objectForKey:[[self class] description]];
  
  if (cell == nil) {
    cell = [[self alloc] initWithStyle:UITableViewCellStyleDefault
                       reuseIdentifier:nil];
    [tableView.dw_reuseCells setObject:cell forKey:[[self class] description]];
  }
  
  if (config) {
    config(cell);
  }
  
  return [cell private_dw_heightForTableView:tableView];
}


+ (CGFloat)dw_heightForTableView:(UITableView *)tableView
                           config:(DWCellConfigBlock)config
                            cache:(DWCacheHeight)cache{
  if (cache) {
    NSDictionary *cacheKeys = cache();
    NSString *key = cacheKeys[kDWCacheUniqueKey];
    NSString *stateKey = cacheKeys[kDWCacheStateKey];
    NSString *shouldUpdate = cacheKeys[kDWRecalculateForStateKey];
    
    NSMutableDictionary *stateDict = tableView.dw_cacheCellHeightDict[key];
    NSString *cacheHeight = stateDict[stateKey];
    
    if (tableView == nil
        || tableView.dw_cacheCellHeightDict.count == 0
        || shouldUpdate.boolValue
        || cacheHeight == nil) {
      CGFloat height = [self dw_heightForTableView:tableView config:config];
      
      if (stateDict == nil) {
        stateDict = [[NSMutableDictionary alloc] init];
        tableView.dw_cacheCellHeightDict[key] = stateDict;
      }
      
//      [stateDict setObject:[NSString stringWithFormat:@"%lf", height] forKey:stateKey];
      
      return height;
    } else if (tableView.dw_cacheCellHeightDict.count != 0
               && cacheHeight != nil
               && cacheHeight.integerValue != 0) {
      return cacheHeight.floatValue;
    }
  }
  
  return [self dw_heightForTableView:tableView config:config];
}



#pragma mark - Private Methods


- (CGFloat)private_dw_heightForIndexPath:(NSIndexPath *)indexPath {
  NSAssert(self.dw_bottomView != nil, @"您未指定cell排列中最后一个视图对象，无法计算cell的高度");

  // 调用方法，确定约束
  [self layoutIfNeeded];
  
  // 通过已确定的约束来得到最下面的控件的Frame； 然后通过Frame 来计算出cell的高度
  CGFloat cellHeight = self.dw_bottomView.frame.size.height + self.dw_bottomView.frame.origin.y;
  cellHeight += self.dw_bottomOffsetToCell;
  
  return cellHeight;
}


- (CGFloat)private_dw_heightForTableView:(UITableView *)tableView {
  NSAssert(self.dw_bottomView != nil, @"您未指定cell排列中最后一个视图对象，无法计算cell的高度");
  
  [self layoutIfNeeded];
  
  CGFloat rowHeight = self.dw_bottomView.frame.size.height + self.dw_bottomView.frame.origin.y;
  rowHeight += self.dw_bottomOffsetToCell;
  
  return rowHeight;
}

@end
